--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
meshchatx/src/backend/markdown_renderer.py 9f75e3db181925ddd253f7fb231af81f9fb8c013 (9f75e3db) Text, 13.23 KB
T8b949e# SPDX-License-Identifier: 0BSD
Tff7b72import T7ee787html
Tff7b72import T7ee787re
Te6edf3_SAFE_LINK_PREFIXES Tff7b72= Tb4b4b4(Ta5d6ff"Ta5d6ffhttps://Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffhttp://Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff#Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmailto:Ta5d6ff"Tb4b4b4)
Te6edf3_UNSAFE_PROTOCOLS Tff7b72= Tb4b4b4(Ta5d6ff"Ta5d6ffjavascript:Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffdata:Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffvbscript:Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6fffile:Ta5d6ff"Tb4b4b4)
Tff7b72def Td2a8ff_safe_hrefTb4b4b4(Te6edf3urlTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3url Tff7b72or Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3urlTb4b4b4, Tffa657strTb4b4b4)Tb4b4b4:
Tff7b72return Ta5d6ff"Ta5d6ff#Ta5d6ff"
Te6edf3trimmed Tff7b72= Te6edf3urlTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Te6edf3u Tff7b72= Te6edf3trimmedTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)
Tff7b72if Tffa657anyTb4b4b4(Te6edf3uTff7b72.Td2a8ffstartswithTb4b4b4(Te6edf3pTb4b4b4) Tff7b72for Te6edf3p Tff7b72in Te6edf3_UNSAFE_PROTOCOLSTb4b4b4)Tb4b4b4:
Tff7b72return Ta5d6ff"Ta5d6ff#Ta5d6ff"
Tff7b72if Te6edf3uTff7b72.Td2a8ffstartswithTb4b4b4(Ta5d6ff"Ta5d6ff//Ta5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72return Ta5d6ff"Ta5d6ff#Ta5d6ff"
Tff7b72if Te6edf3trimmedTff7b72.Td2a8ffstartswithTb4b4b4(Ta5d6ff"Tffea00\\Tffea00\\Ta5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72return Ta5d6ff"Ta5d6ff#Ta5d6ff"
Tff7b72if Tffa657anyTb4b4b4(Te6edf3uTff7b72.Td2a8ffstartswithTb4b4b4(Te6edf3pTb4b4b4) Tff7b72for Te6edf3p Tff7b72in Te6edf3_SAFE_LINK_PREFIXESTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3url
Tff7b72if Ta5d6ff"Ta5d6ff:Ta5d6ff" Tff7b72in Te6edf3uTff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4)Tb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4:
Tff7b72return Ta5d6ff"Ta5d6ff#Ta5d6ff"
Tff7b72return Te6edf3url
Tff7b72class T56d364MarkdownRendererTb4b4b4:
T8b949e"""A simple Markdown to HTML renderer."""
Te6edf3_heading_idsTb4b4b4: Tffa657dictTb4b4b4[Tffa657strTb4b4b4, Tffa657intTb4b4b4] Tff7b72= Tb4b4b4{Tb4b4b4}
Tf0883e@classmethod
Tff7b72def Td2a8ff_reset_heading_idsTb4b4b4(Tff7b72clsTb4b4b4)Tb4b4b4:
Tff7b72clsTff7b72.Td2a8ff_heading_ids Tff7b72= Tb4b4b4{Tb4b4b4}
Tf0883e@classmethod
Tff7b72def Td2a8ff_heading_idTb4b4b4(Tff7b72clsTb4b4b4, Te6edf3textTb4b4b4, Te6edf3levelTb4b4b4)Tb4b4b4:
Te6edf3slug_base Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff[^Ta5d6ff\Ta5d6ffwTa5d6ff\Ta5d6ffs-]Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4, Te6edf3htmlTff7b72.Td2a8ffunescapeTb4b4b4(Te6edf3textTb4b4b4)Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)
Te6edf3slug_base Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff[-Ta5d6ff\Ta5d6ffs]+Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff-Ta5d6ff"Tb4b4b4, Te6edf3slug_baseTb4b4b4) Tff7b72or Ta5d6ff"Ta5d6ffsectionTa5d6ff"
Te6edf3key Tff7b72= Ta5d6fffTa5d6ff"Tffd700{Te6edf3levelTffd700}Ta5d6ff:Tffd700{Te6edf3slug_baseTffd700}Ta5d6ff"
Te6edf3count Tff7b72= Tff7b72clsTff7b72.Td2a8ff_heading_idsTff7b72.Td2a8ffgetTb4b4b4(Te6edf3keyTb4b4b4, T79c0ff0Tb4b4b4)
Tff7b72clsTff7b72.Td2a8ff_heading_idsTb4b4b4[Te6edf3keyTb4b4b4] Tff7b72= Te6edf3count Tff7b72+ T79c0ff1
Tff7b72if Te6edf3countTb4b4b4:
Tff7b72return Ta5d6fffTa5d6ff"Tffd700{Te6edf3slug_baseTffd700}Ta5d6ff-Tffd700{Te6edf3count Tff7b72+ T79c0ff1Tffd700}Ta5d6ff"
Tff7b72return Te6edf3slug_base
Tf0883e@staticmethod
Tff7b72def Td2a8ffrenderTb4b4b4(Te6edf3textTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3textTb4b4b4:
Tff7b72return Ta5d6ff"Ta5d6ff"
Te6edf3MarkdownRendererTff7b72.Td2a8ff_reset_heading_idsTb4b4b4(Tb4b4b4)
T8b949e# Escape HTML entities first to prevent XSS
T8b949e# Use a more limited escape if we want to allow some things,
T8b949e# but for docs, full escape is safest.
Te6edf3text Tff7b72= Te6edf3htmlTff7b72.Td2a8ffescapeTb4b4b4(Te6edf3textTb4b4b4)
T8b949e# Fenced code blocks - process these FIRST and replace with placeholders
T8b949e# to avoid other regexes mangling the code content
Te6edf3code_blocks Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72def Td2a8ffcode_block_placeholderTb4b4b4(Te6edf3matchTb4b4b4)Tb4b4b4:
Te6edf3lang Tff7b72= Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff1Tb4b4b4) Tff7b72or Ta5d6ff"Ta5d6ff"
Te6edf3code Tff7b72= Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff2Tb4b4b4)
Te6edf3placeholder Tff7b72= Ta5d6fffTa5d6ff"Ta5d6ff[[CBTffd700{Tffa657lenTb4b4b4(Te6edf3code_blocksTb4b4b4)Tffd700}Ta5d6ff]]Ta5d6ff"
Te6edf3code_blocksTff7b72.Td2a8ffappendTb4b4b4(
Ta5d6fffTa5d6ff'Ta5d6ff<pre class=Ta5d6ff"Ta5d6ffbg-gray-800 dark:bg-zinc-900 text-zinc-100 dark:text-zinc-100 p-4 rounded-lg my-4 overflow-x-auto border border-gray-700 dark:border-zinc-800 font-mono text-smTa5d6ff"Ta5d6ff><code class=Ta5d6ff"Ta5d6fflanguage-Tffd700{Te6edf3langTffd700}Ta5d6ff text-inheritTa5d6ff"Ta5d6ff>Tffd700{Te6edf3codeTffd700}Ta5d6ff</code></pre>Ta5d6ff'Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3placeholder
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff```(Ta5d6ff\Ta5d6ffw+)?Ta5d6ff\Ta5d6ffn(.*?)Ta5d6ff\Ta5d6ffn```Ta5d6ff"Tb4b4b4,
Te6edf3code_block_placeholderTb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffDOTALLTb4b4b4,
Tb4b4b4)
T8b949e# Inline code before emphasis so snake_case / rst spans are not
T8b949e# mangled by underscore italic (changelog uses both code spans).
Te6edf3inline_codesTb4b4b4: Tffa657listTb4b4b4[Tffa657strTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72def Td2a8ffinline_code_placeholderTb4b4b4(Te6edf3matchTb4b4b4)Tb4b4b4:
Te6edf3code Tff7b72= Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff1Tb4b4b4)
Te6edf3placeholder Tff7b72= Ta5d6fffTa5d6ff"Ta5d6ff[[ICTffd700{Tffa657lenTb4b4b4(Te6edf3inline_codesTb4b4b4)Tffd700}Ta5d6ff]]Ta5d6ff"
Te6edf3inline_codesTff7b72.Td2a8ffappendTb4b4b4(
Ta5d6fffTa5d6ff'Ta5d6ff<code class=Ta5d6ff"Ta5d6ffbg-gray-100 dark:bg-zinc-800 px-1.5 py-0.5 Ta5d6ff'
Ta5d6fffTa5d6ff"Ta5d6ffrounded-sm text-pink-600 dark:text-pink-400 font-mono Ta5d6ff"
Ta5d6fffTa5d6ff'Ta5d6fftext-[0.9em]Ta5d6ff"Ta5d6ff>Tffd700{Te6edf3codeTffd700}Ta5d6ff</code>Ta5d6ff'Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3placeholder
T8b949e# Double-backtick spans first (CommonMark / changelog RST-style).
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff``([^`]+)``Ta5d6ff"Tb4b4b4, Te6edf3inline_code_placeholderTb4b4b4, Te6edf3textTb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff`([^`]+)`Ta5d6ff"Tb4b4b4, Te6edf3inline_code_placeholderTb4b4b4, Te6edf3textTb4b4b4)
Te6edf3text Tff7b72= Te6edf3MarkdownRendererTff7b72.Td2a8ff_render_tablesTb4b4b4(Te6edf3textTb4b4b4)
T8b949e# Horizontal Rules
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^---+$Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff'Ta5d6ff<hr class=Ta5d6ff"Ta5d6ffmy-8 border-t border-gray-200 dark:border-zinc-800Ta5d6ff"Ta5d6ff>Ta5d6ff'Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
T8b949e# Headers
Tff7b72def Td2a8ffheading_replTb4b4b4(Te6edf3levelTb4b4b4, Te6edf3classesTb4b4b4)Tb4b4b4:
Tff7b72def Td2a8ffreplTb4b4b4(Te6edf3matchTb4b4b4)Tb4b4b4:
Te6edf3title Tff7b72= Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff1Tb4b4b4)
Te6edf3heading_id Tff7b72= Te6edf3MarkdownRendererTff7b72.Td2a8ff_heading_idTb4b4b4(Te6edf3titleTb4b4b4, Te6edf3levelTb4b4b4)
Tff7b72return Tb4b4b4(
Ta5d6fffTa5d6ff'Ta5d6ff<hTffd700{Te6edf3levelTffd700}Ta5d6ff id=Ta5d6ff"Tffd700{Te6edf3heading_idTffd700}Ta5d6ff"Ta5d6ff class=Ta5d6ff"Tffd700{Te6edf3classesTffd700}Ta5d6ff"Ta5d6ff>Tffd700{Te6edf3titleTffd700}Ta5d6ff</hTffd700{Te6edf3levelTffd700}Ta5d6ff>Ta5d6ff'
Tb4b4b4)
Tff7b72return Te6edf3repl
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^# (.*)$Ta5d6ff"Tb4b4b4,
Te6edf3heading_replTb4b4b4(
T79c0ff1Tb4b4b4,
Ta5d6ff"Ta5d6fftext-3xl font-bold mt-8 mb-4 text-gray-900 dark:text-zinc-100 scroll-mt-24Ta5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^## (.*)$Ta5d6ff"Tb4b4b4,
Te6edf3heading_replTb4b4b4(
T79c0ff2Tb4b4b4,
Ta5d6ff"Ta5d6fftext-2xl font-bold mt-8 mb-3 text-gray-900 dark:text-zinc-100 scroll-mt-24 border-b border-gray-200 dark:border-zinc-800 pb-2Ta5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^### (.*)$Ta5d6ff"Tb4b4b4,
Te6edf3heading_replTb4b4b4(
T79c0ff3Tb4b4b4,
Ta5d6ff"Ta5d6fftext-xl font-semibold mt-6 mb-2 text-gray-900 dark:text-zinc-100 scroll-mt-24Ta5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^#### (.*)$Ta5d6ff"Tb4b4b4,
Te6edf3heading_replTb4b4b4(
T79c0ff4Tb4b4b4,
Ta5d6ff"Ta5d6fftext-lg font-semibold mt-4 mb-2 text-gray-900 dark:text-zinc-100 scroll-mt-24Ta5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
T8b949e# Bold and Italic (underscore italic requires word boundaries so
T8b949e# identifiers like local_hops_delta and api_extensions stay intact).
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff\Ta5d6ff*Ta5d6ff\Ta5d6ff*Ta5d6ff\Ta5d6ff*(.+?)Ta5d6ff\Ta5d6ff*Ta5d6ff\Ta5d6ff*Ta5d6ff\Ta5d6ff*Ta5d6ff"Tb4b4b4, Ta5d6ffrTa5d6ff"Ta5d6ff<strong><em>Ta5d6ff\Ta5d6ff1</em></strong>Ta5d6ff"Tb4b4b4, Te6edf3textTb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff\Ta5d6ff*Ta5d6ff\Ta5d6ff*(.+?)Ta5d6ff\Ta5d6ff*Ta5d6ff\Ta5d6ff*Ta5d6ff"Tb4b4b4, Ta5d6ffrTa5d6ff"Ta5d6ff<strong>Ta5d6ff\Ta5d6ff1</strong>Ta5d6ff"Tb4b4b4, Te6edf3textTb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff\Ta5d6ff*(?!Ta5d6ff\Ta5d6ffs)(.+?)(?<!Ta5d6ff\Ta5d6ffs)Ta5d6ff\Ta5d6ff*Ta5d6ff"Tb4b4b4, Ta5d6ffrTa5d6ff"Ta5d6ff<em>Ta5d6ff\Ta5d6ff1</em>Ta5d6ff"Tb4b4b4, Te6edf3textTb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff___(.+?)___Ta5d6ff"Tb4b4b4, Ta5d6ffrTa5d6ff"Ta5d6ff<strong><em>Ta5d6ff\Ta5d6ff1</em></strong>Ta5d6ff"Tb4b4b4, Te6edf3textTb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff(?<!Ta5d6ff\Ta5d6ffw)__(?!Ta5d6ff\Ta5d6ffs)(.+?)(?<!Ta5d6ff\Ta5d6ffs)__(?!Ta5d6ff\Ta5d6ffw)Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff"Ta5d6ff<strong>Ta5d6ff\Ta5d6ff1</strong>Ta5d6ff"Tb4b4b4,
Te6edf3textTb4b4b4,
Tb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff(?<!Ta5d6ff\Ta5d6ffw)_(?!Ta5d6ff\Ta5d6ffs)(.+?)(?<!Ta5d6ff\Ta5d6ffs)_(?!Ta5d6ff\Ta5d6ffw)Ta5d6ff"Tb4b4b4, Ta5d6ffrTa5d6ff"Ta5d6ff<em>Ta5d6ff\Ta5d6ff1</em>Ta5d6ff"Tb4b4b4, Te6edf3textTb4b4b4)
T8b949e# Strikethrough
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff~~(.*?)~~Ta5d6ff"Tb4b4b4, Ta5d6ffrTa5d6ff"Ta5d6ff<del>Ta5d6ff\Ta5d6ff1</del>Ta5d6ff"Tb4b4b4, Te6edf3textTb4b4b4)
T8b949e# Task lists
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^[-*] Ta5d6ff\Ta5d6ff[ Ta5d6ff\Ta5d6ff] (.*)$Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff'Ta5d6ff<li class=Ta5d6ff"Ta5d6ffflex items-start gap-2 list-noneTa5d6ff"Ta5d6ff><input type=Ta5d6ff"Ta5d6ffcheckboxTa5d6ff"Ta5d6ff disabled class=Ta5d6ff"Ta5d6ffmt-1Ta5d6ff"Ta5d6ff> <span>Ta5d6ff\Ta5d6ff1</span></li>Ta5d6ff'Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^[-*] Ta5d6ff\Ta5d6ff[xTa5d6ff\Ta5d6ff] (.*)$Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff'Ta5d6ff<li class=Ta5d6ff"Ta5d6ffflex items-start gap-2 list-noneTa5d6ff"Ta5d6ff><input type=Ta5d6ff"Ta5d6ffcheckboxTa5d6ff"Ta5d6ff checked disabled class=Ta5d6ff"Ta5d6ffmt-1Ta5d6ff"Ta5d6ff> <span class=Ta5d6ff"Ta5d6ffline-through opacity-50Ta5d6ff"Ta5d6ff>Ta5d6ff\Ta5d6ff1</span></li>Ta5d6ff'Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
T8b949e# Links (href sanitized to prevent javascript:/data: XSS)
Tff7b72def Td2a8fflink_replTb4b4b4(Te6edf3matchTb4b4b4)Tb4b4b4:
Te6edf3labelTb4b4b4, Te6edf3url Tff7b72= Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4, Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff2Tb4b4b4)
Te6edf3safe_url Tff7b72= Te6edf3_safe_hrefTb4b4b4(Te6edf3urlTb4b4b4)
Te6edf3is_external Tff7b72= Tffa657anyTb4b4b4(
Te6edf3safe_urlTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffstartswithTb4b4b4(Te6edf3pTb4b4b4)
Tff7b72for Te6edf3p Tff7b72in Tb4b4b4(Ta5d6ff"Ta5d6ffhttps://Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffhttp://Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmailto:Ta5d6ff"Tb4b4b4)
Tb4b4b4)
Te6edf3target Tff7b72= Ta5d6ff'Ta5d6ff target=Ta5d6ff"Ta5d6ff_blankTa5d6ff"Ta5d6ff rel=Ta5d6ff"Ta5d6ffnoopener noreferrerTa5d6ff"Ta5d6ff' Tff7b72if Te6edf3is_external Tff7b72else Ta5d6ff"Ta5d6ff"
Tff7b72return Tb4b4b4(
Ta5d6fffTa5d6ff'Ta5d6ff<a href=Ta5d6ff"Tffd700{Te6edf3htmlTff7b72.Td2a8ffescapeTb4b4b4(Te6edf3safe_urlTb4b4b4)Tffd700}Ta5d6ff"Ta5d6ff class=Ta5d6ff"Ta5d6fftext-blue-600 Ta5d6ff'
Ta5d6fffTa5d6ff'Ta5d6ffdark:text-blue-400 hover:underlineTa5d6ff"Tffd700{Te6edf3targetTffd700}Ta5d6ff>Tffd700{Te6edf3labelTffd700}Ta5d6ff</a>Ta5d6ff'
Tb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff\Ta5d6ff[([^Ta5d6ff\Ta5d6ff]]+)Ta5d6ff\Ta5d6ff]Ta5d6ff\Ta5d6ff(([^)]+)Ta5d6ff\Ta5d6ff)Ta5d6ff"Tb4b4b4,
Te6edf3link_replTb4b4b4,
Te6edf3textTb4b4b4,
Tb4b4b4)
T8b949e# Images (src sanitized)
Tff7b72def Td2a8ffimg_replTb4b4b4(Te6edf3matchTb4b4b4)Tb4b4b4:
Te6edf3altTb4b4b4, Te6edf3src Tff7b72= Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4, Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff2Tb4b4b4)
Te6edf3safe_src Tff7b72= Te6edf3_safe_hrefTb4b4b4(Te6edf3srcTb4b4b4)
Tff7b72if Te6edf3safe_src Tff7b72== Ta5d6ff"Ta5d6ff#Ta5d6ff"Tb4b4b4:
Tff7b72return Te6edf3htmlTff7b72.Td2a8ffescapeTb4b4b4(Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff0Tb4b4b4)Tb4b4b4)
Tff7b72return Ta5d6fffTa5d6ff'Ta5d6ff<div class=Ta5d6ff"Ta5d6ffmy-6Ta5d6ff"Ta5d6ff><img src=Ta5d6ff"Tffd700{Te6edf3htmlTff7b72.Td2a8ffescapeTb4b4b4(Te6edf3safe_srcTb4b4b4)Tffd700}Ta5d6ff"Ta5d6ff alt=Ta5d6ff"Tffd700{Te6edf3altTffd700}Ta5d6ff"Ta5d6ff class=Ta5d6ff"Ta5d6ffmax-w-full h-auto rounded-xl shadow-lg border border-gray-100 dark:border-zinc-800Ta5d6ff"Ta5d6ff></div>Ta5d6ff'
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff!Ta5d6ff\Ta5d6ff[([^Ta5d6ff\Ta5d6ff]]*)Ta5d6ff\Ta5d6ff]Ta5d6ff\Ta5d6ff(([^)]+)Ta5d6ff\Ta5d6ff)Ta5d6ff"Tb4b4b4,
Te6edf3img_replTb4b4b4,
Te6edf3textTb4b4b4,
Tb4b4b4)
T8b949e# Blockquotes
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^> (.*)$Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff'Ta5d6ff<blockquote class=Ta5d6ff"Ta5d6ffborder-l-4 border-blue-500/50 pl-4 py-2 my-6 italic bg-gray-50 dark:bg-zinc-900/50 text-gray-700 dark:text-zinc-300 rounded-r-lgTa5d6ff"Ta5d6ff>Ta5d6ff\Ta5d6ff1</blockquote>Ta5d6ff'Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
T8b949e# Lists - Simple single level for now to keep it predictable
Tff7b72def Td2a8ffunordered_list_replTb4b4b4(Te6edf3matchTb4b4b4)Tb4b4b4:
Te6edf3items Tff7b72= Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff0Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff"Tb4b4b4)
Te6edf3html_items Tff7b72= Ta5d6ff"Ta5d6ff"
Tff7b72for Te6edf3i Tff7b72in Te6edf3itemsTb4b4b4:
T8b949e# Check if it's already a task list item
Tff7b72if Ta5d6ff'Ta5d6fftype=Ta5d6ff"Ta5d6ffcheckboxTa5d6ff"Ta5d6ff' Tff7b72in Te6edf3iTb4b4b4:
Te6edf3html_items Tff7b72+Tff7b72= Te6edf3i
Tff7b72elseTb4b4b4:
Te6edf3content Tff7b72= Te6edf3iTb4b4b4[T79c0ff2Tb4b4b4:Tb4b4b4]Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Te6edf3html_items Tff7b72+Tff7b72= Ta5d6fffTa5d6ff'Ta5d6ff<li class=Ta5d6ff"Ta5d6ffml-4 mb-1 list-disc text-gray-700 dark:text-zinc-300Ta5d6ff"Ta5d6ff>Tffd700{Te6edf3contentTffd700}Ta5d6ff</li>Ta5d6ff'
Tff7b72return Ta5d6fffTa5d6ff'Ta5d6ff<ul class=Ta5d6ff"Ta5d6ffmy-4 space-y-1Ta5d6ff"Ta5d6ff>Tffd700{Te6edf3html_itemsTffd700}Ta5d6ff</ul>Ta5d6ff'
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff((?:^[*-] .*Ta5d6ff\Ta5d6ffn?)+)Ta5d6ff"Tb4b4b4,
Te6edf3unordered_list_replTb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
Tff7b72def Td2a8ffordered_list_replTb4b4b4(Te6edf3matchTb4b4b4)Tb4b4b4:
Te6edf3items Tff7b72= Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff0Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff"Tb4b4b4)
Te6edf3html_items Tff7b72= Ta5d6ff"Ta5d6ff"
Tff7b72for Te6edf3i Tff7b72in Te6edf3itemsTb4b4b4:
Te6edf3content Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff^Ta5d6ff\Ta5d6ffd+Ta5d6ff\Ta5d6ff. Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4, Te6edf3iTb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Te6edf3html_items Tff7b72+Tff7b72= Ta5d6fffTa5d6ff'Ta5d6ff<li class=Ta5d6ff"Ta5d6ffml-4 mb-1 list-decimal text-gray-700 dark:text-zinc-300Ta5d6ff"Ta5d6ff>Tffd700{Te6edf3contentTffd700}Ta5d6ff</li>Ta5d6ff'
Tff7b72return Ta5d6fffTa5d6ff'Ta5d6ff<ol class=Ta5d6ff"Ta5d6ffmy-4 space-y-1Ta5d6ff"Ta5d6ff>Tffd700{Te6edf3html_itemsTffd700}Ta5d6ff</ol>Ta5d6ff'
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff((?:^Ta5d6ff\Ta5d6ffd+Ta5d6ff\Ta5d6ff. .*Ta5d6ff\Ta5d6ffn?)+)Ta5d6ff"Tb4b4b4,
Te6edf3ordered_list_replTb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
T8b949e# Paragraphs - double newline to p tag
Te6edf3parts Tff7b72= Te6edf3textTff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Tffea00\nTffea00\nTa5d6ff"Tb4b4b4)
Te6edf3processed_parts Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3part Tff7b72in Te6edf3partsTb4b4b4:
Te6edf3part Tff7b72= Te6edf3partTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3partTb4b4b4:
Tff7b72continue
T8b949e# If it's a placeholder for code block, don't wrap in <p>
Tff7b72if Te6edf3reTff7b72.Td2a8fffullmatchTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff\Ta5d6ff[Ta5d6ff\Ta5d6ff[(?:CB|IC)Ta5d6ff\Ta5d6ffd+Ta5d6ff\Ta5d6ff]Ta5d6ff\Ta5d6ff]Ta5d6ff"Tb4b4b4, Te6edf3partTb4b4b4)Tb4b4b4:
Te6edf3processed_partsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3partTb4b4b4)
Tff7b72continue
T8b949e# If it already starts with a block tag, don't wrap in <p>
Tff7b72if Te6edf3reTff7b72.Td2a8ffmatchTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff^<(hTa5d6ff\Ta5d6ffd|ul|ol|li|blockquote|hr|div|table)Ta5d6ff"Tb4b4b4, Te6edf3partTb4b4b4)Tb4b4b4:
Te6edf3processed_partsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3partTb4b4b4)
Tff7b72elseTb4b4b4:
T8b949e# Replace single newlines with <br> for line breaks within paragraphs
Te6edf3part Tff7b72= Te6edf3partTff7b72.Td2a8ffreplaceTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff<br>Ta5d6ff"Tb4b4b4)
Te6edf3processed_partsTff7b72.Td2a8ffappendTb4b4b4(
Ta5d6fffTa5d6ff'Ta5d6ff<p class=Ta5d6ff"Ta5d6ffmy-4 leading-relaxed text-gray-800 dark:text-zinc-200Ta5d6ff"Ta5d6ff>Tffd700{Te6edf3partTffd700}Ta5d6ff</p>Ta5d6ff'Tb4b4b4,
Tb4b4b4)
Te6edf3text Tff7b72= Ta5d6ff"Tffea00\nTa5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Te6edf3processed_partsTb4b4b4)
T8b949e# Restore inline code then fenced blocks in one pass each (avoid O(n*m) loops).
Tff7b72def Td2a8ff_restore_inlineTb4b4b4(Te6edf3matchTb4b4b4)Tb4b4b4:
Te6edf3idx Tff7b72= Tffa657intTb4b4b4(Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4)
Tff7b72if T79c0ff0 Tff7b72<Tff7b72= Te6edf3idx Tff7b72< Tffa657lenTb4b4b4(Te6edf3inline_codesTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3inline_codesTb4b4b4[Te6edf3idxTb4b4b4]
Tff7b72return Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff0Tb4b4b4)
Tff7b72def Td2a8ff_restore_fencedTb4b4b4(Te6edf3matchTb4b4b4)Tb4b4b4:
Te6edf3idx Tff7b72= Tffa657intTb4b4b4(Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4)
Tff7b72if T79c0ff0 Tff7b72<Tff7b72= Te6edf3idx Tff7b72< Tffa657lenTb4b4b4(Te6edf3code_blocksTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3code_blocksTb4b4b4[Te6edf3idxTb4b4b4]
Tff7b72return Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff0Tb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff\Ta5d6ff[Ta5d6ff\Ta5d6ff[IC(Ta5d6ff\Ta5d6ffd+)Ta5d6ff\Ta5d6ff]Ta5d6ff\Ta5d6ff]Ta5d6ff"Tb4b4b4, Te6edf3_restore_inlineTb4b4b4, Te6edf3textTb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff\Ta5d6ff[Ta5d6ff\Ta5d6ff[CB(Ta5d6ff\Ta5d6ffd+)Ta5d6ff\Ta5d6ff]Ta5d6ff\Ta5d6ff]Ta5d6ff"Tb4b4b4, Te6edf3_restore_fencedTb4b4b4, Te6edf3textTb4b4b4)
Tff7b72return Te6edf3text
Tf0883e@staticmethod
Tff7b72def Td2a8ff_is_table_rowTb4b4b4(Te6edf3lineTb4b4b4)Tb4b4b4:
Te6edf3stripped Tff7b72= Te6edf3lineTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Tff7b72return Tb4b4b4(
Te6edf3strippedTff7b72.Td2a8ffstartswithTb4b4b4(Ta5d6ff"Ta5d6ff|Ta5d6ff"Tb4b4b4)
Tff7b72and Te6edf3strippedTff7b72.Td2a8ffendswithTb4b4b4(Ta5d6ff"Ta5d6ff|Ta5d6ff"Tb4b4b4)
Tff7b72and Te6edf3strippedTff7b72.Td2a8ffcountTb4b4b4(Ta5d6ff"Ta5d6ff|Ta5d6ff"Tb4b4b4) Tff7b72>Tff7b72= T79c0ff2
Tb4b4b4)
Tf0883e@staticmethod
Tff7b72def Td2a8ff_split_table_cellsTb4b4b4(Te6edf3lineTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4[Te6edf3cellTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4) Tff7b72for Te6edf3cell Tff7b72in Te6edf3lineTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Ta5d6ff"Ta5d6ff|Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Ta5d6ff|Ta5d6ff"Tb4b4b4)Tb4b4b4]
Tf0883e@staticmethod
Tff7b72def Td2a8ff_is_table_separatorTb4b4b4(Te6edf3lineTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3MarkdownRendererTff7b72.Td2a8ff_is_table_rowTb4b4b4(Te6edf3lineTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False
Te6edf3cells Tff7b72= Te6edf3MarkdownRendererTff7b72.Td2a8ff_split_table_cellsTb4b4b4(Te6edf3lineTb4b4b4)
Tff7b72if Tff7b72not Te6edf3cellsTb4b4b4:
Tff7b72return Tff7b72False
Tff7b72return Tffa657allTb4b4b4(Te6edf3reTff7b72.Td2a8fffullmatchTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff:?-Ta5d6ff{Ta5d6ff3,}:?Ta5d6ff"Tb4b4b4, Te6edf3cellTb4b4b4) Tff7b72for Te6edf3cell Tff7b72in Te6edf3cellsTb4b4b4)
Tf0883e@staticmethod
Tff7b72def Td2a8ff_table_block_to_htmlTb4b4b4(Te6edf3linesTb4b4b4)Tb4b4b4:
Te6edf3header_cells Tff7b72= Te6edf3MarkdownRendererTff7b72.Td2a8ff_split_table_cellsTb4b4b4(Te6edf3linesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4)
Te6edf3body_rows Tff7b72= Tb4b4b4[
Te6edf3MarkdownRendererTff7b72.Td2a8ff_split_table_cellsTb4b4b4(Te6edf3rowTb4b4b4)
Tff7b72for Te6edf3row Tff7b72in Te6edf3linesTb4b4b4[T79c0ff2Tb4b4b4:Tb4b4b4]
Tff7b72if Te6edf3MarkdownRendererTff7b72.Td2a8ff_is_table_rowTb4b4b4(Te6edf3rowTb4b4b4)
Tb4b4b4]
Te6edf3thead Tff7b72= Ta5d6ff"Ta5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(
Ta5d6fffTa5d6ff'Ta5d6ff<th class=Ta5d6ff"Ta5d6ffpx-3 py-2 text-left font-boldTa5d6ff"Ta5d6ff>Tffd700{Te6edf3cellTffd700}Ta5d6ff</th>Ta5d6ff'
Tff7b72for Te6edf3cell Tff7b72in Te6edf3header_cells
Tb4b4b4)
Te6edf3tbody_rows Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3row Tff7b72in Te6edf3body_rowsTb4b4b4:
Te6edf3padded Tff7b72= Te6edf3row Tff7b72+ Tb4b4b4[Ta5d6ff"Ta5d6ff"Tb4b4b4] Tff7b72* Tb4b4b4(Tffa657lenTb4b4b4(Te6edf3header_cellsTb4b4b4) Tff7b72- Tffa657lenTb4b4b4(Te6edf3rowTb4b4b4)Tb4b4b4)
Te6edf3cells Tff7b72= Ta5d6ff"Ta5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(
Ta5d6fffTa5d6ff'Ta5d6ff<td class=Ta5d6ff"Ta5d6ffpx-3 py-2 align-topTa5d6ff"Ta5d6ff>Tffd700{Te6edf3cellTffd700}Ta5d6ff</td>Ta5d6ff'
Tff7b72for Te6edf3cell Tff7b72in Te6edf3paddedTb4b4b4[Tb4b4b4: Tffa657lenTb4b4b4(Te6edf3header_cellsTb4b4b4)Tb4b4b4]
Tb4b4b4)
Te6edf3tbody_rowsTff7b72.Td2a8ffappendTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff<tr>Tffd700{Te6edf3cellsTffd700}Ta5d6ff</tr>Ta5d6ff"Tb4b4b4)
Te6edf3tbody Tff7b72= Ta5d6ff"Ta5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Te6edf3tbody_rowsTb4b4b4)
Tff7b72return Tb4b4b4(
Ta5d6ff'Ta5d6ff<div class=Ta5d6ff"Ta5d6ffoverflow-x-auto my-6Ta5d6ff"Ta5d6ff>Ta5d6ff'
Ta5d6ff'Ta5d6ff<table class=Ta5d6ff"Ta5d6ffw-full border-collapse text-smTa5d6ff"Ta5d6ff>Ta5d6ff'
Ta5d6fffTa5d6ff"Ta5d6ff<thead><tr>Tffd700{Te6edf3theadTffd700}Ta5d6ff</tr></thead>Ta5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ff<tbody>Tffd700{Te6edf3tbodyTffd700}Ta5d6ff</tbody>Ta5d6ff"
Ta5d6ff"Ta5d6ff</table></div>Ta5d6ff"
Tb4b4b4)
Tf0883e@staticmethod
Tff7b72def Td2a8ff_render_tablesTb4b4b4(Te6edf3textTb4b4b4)Tb4b4b4:
Te6edf3lines Tff7b72= Te6edf3textTff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff"Tb4b4b4)
Te6edf3out Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3i Tff7b72= T79c0ff0
Tff7b72while Te6edf3i Tff7b72< Tffa657lenTb4b4b4(Te6edf3linesTb4b4b4)Tb4b4b4:
Te6edf3line Tff7b72= Te6edf3linesTb4b4b4[Te6edf3iTb4b4b4]
Tff7b72if Tb4b4b4(
Te6edf3i Tff7b72+ T79c0ff1 Tff7b72< Tffa657lenTb4b4b4(Te6edf3linesTb4b4b4)
Tff7b72and Te6edf3MarkdownRendererTff7b72.Td2a8ff_is_table_rowTb4b4b4(Te6edf3lineTb4b4b4)
Tff7b72and Te6edf3MarkdownRendererTff7b72.Td2a8ff_is_table_separatorTb4b4b4(Te6edf3linesTb4b4b4[Te6edf3i Tff7b72+ T79c0ff1Tb4b4b4]Tb4b4b4)
Tb4b4b4)Tb4b4b4:
Te6edf3block Tff7b72= Tb4b4b4[Te6edf3lineTb4b4b4, Te6edf3linesTb4b4b4[Te6edf3i Tff7b72+ T79c0ff1Tb4b4b4]Tb4b4b4]
Te6edf3i Tff7b72+Tff7b72= T79c0ff2
Tff7b72while Te6edf3i Tff7b72< Tffa657lenTb4b4b4(Te6edf3linesTb4b4b4) Tff7b72and Te6edf3MarkdownRendererTff7b72.Td2a8ff_is_table_rowTb4b4b4(Te6edf3linesTb4b4b4[Te6edf3iTb4b4b4]Tb4b4b4)Tb4b4b4:
Te6edf3blockTff7b72.Td2a8ffappendTb4b4b4(Te6edf3linesTb4b4b4[Te6edf3iTb4b4b4]Tb4b4b4)
Te6edf3i Tff7b72+Tff7b72= T79c0ff1
Te6edf3outTff7b72.Td2a8ffappendTb4b4b4(Te6edf3MarkdownRendererTff7b72.Td2a8ff_table_block_to_htmlTb4b4b4(Te6edf3blockTb4b4b4)Tb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3outTff7b72.Td2a8ffappendTb4b4b4(Te6edf3lineTb4b4b4)
Te6edf3i Tff7b72+Tff7b72= T79c0ff1
Tff7b72return Ta5d6ff"Tffea00\nTa5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Te6edf3outTb4b4b4)
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────